package com.syjy.container;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.syjy.DataExchangeException;
import com.syjy.tunnelinfo.BaseTunnelInfo;
import com.syjy.tunnelinfo.TunnelStatus;
import com.syjy.tunnelworker.BaseProtocolTunnel;
import com.syjy.tunnelworker.gathers.DataGatherInterface;
import com.syjy.tunnelworker.senders.DataSenderInterface;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 装载通道对象的容器
 *
 * @author 修唯xiuwei
 * @version 3.0
 */
@Slf4j
public class ProtocolTunnelContainer {

	/**
	 * 通道集合
	 */
	private Map<String, BaseProtocolTunnel> tunnels = new ConcurrentHashMap<>();


	/**
	 * 定时任务集合
	 */
	private Map<String, Callable> tasks = new ConcurrentHashMap<>();


	/**
	 * 单例构造
	 */
	private ProtocolTunnelContainer() {
		RecurringTaskContainer.getInstance().addRecurringCallable(5 * 60, "通道状态巡检任务", new CheckTunnelStatusTask());
	}

	/**
	 * 单例
	 *
	 * @return 实例
	 */
	public static final ProtocolTunnelContainer getInstance() {
		return LazyHolder.INSTANCE;
	}

	/**
	 * 获取tunnelID下的 tunnel
	 *
	 * @param tunnelId 通道id
	 * @return BaseProtocolTunnel 通道
	 */
	public BaseProtocolTunnel getTunnel(String tunnelId) {
		if (this.tunnels.containsKey(tunnelId)) {
			return this.tunnels.get(tunnelId);
		}
		return null;
	}

	/**
	 * 获取所有的 tunnel

	 * @return BaseProtocolTunnel 通道
	 */
	public Map<String, BaseProtocolTunnel> getAllTunnel() {
		return this.tunnels;
	}


	/**
	 * 向集合中置入tunnel
	 *
	 * @param tunnel 通道对象
	 * @return 返回置入的tunnel
	 */
	public BaseProtocolTunnel addTunnel(BaseProtocolTunnel tunnel) {
		this.tunnels.put(tunnel.getTunnelId(), tunnel);
		return tunnel;
	}

	/**
	 * 删除隧道 同时删除定时更新数据任务
	 *
	 * @param tunnelId 隧道id
	 */
	public void removeTunnel(String tunnelId) {
		this.tunnels.remove(tunnelId);
		stopUpdateTask(tunnelId);
	}

	/**
	 * 停止更新任务
	 *
	 * @param tunnelId 通道id
	 */
	public void stopUpdateTask(String tunnelId) {
		if (this.tasks.containsKey(tunnelId)) {
			RecurringTaskContainer.getInstance().removeTask(tasks.get(tunnelId));
			this.tasks.remove(tunnelId);
		}
	}

	/**
	 * 添加数据读取任务
	 *
	 * @param baseProtocolTunnel 通道对象
	 */
	public void addUpdateDateTask(BaseProtocolTunnel baseProtocolTunnel) {
		if (this.tasks.containsKey(baseProtocolTunnel.getTunnelId())) {
			RecurringTaskContainer.getInstance().removeTask(this.tasks.get(baseProtocolTunnel.getTunnelId()));
		}
		Callable callable = null;
		if (baseProtocolTunnel instanceof DataGatherInterface) {
			callable = RecurringTaskContainer.getInstance().addRecurringTask(baseProtocolTunnel.getTunnelInfo().getRefreshInterval(), "采集通道数据更新任务" + baseProtocolTunnel.getTunnelInfo().getTunnelName(), () -> {
				if (TunnelStatus.ABLE_STATUS.contains(baseProtocolTunnel.getTunnelStatus())) {
					((DataGatherInterface) baseProtocolTunnel).getDataFromProtocol();
				}
				return null;
			});
		} else if (baseProtocolTunnel instanceof DataSenderInterface) {
			callable = RecurringTaskContainer.getInstance().addRecurringTask(baseProtocolTunnel.getTunnelInfo().getRefreshInterval(), "转发通道数据更新任务" + baseProtocolTunnel.getTunnelInfo().getTunnelName(), () -> {
				if (TunnelStatus.ABLE_STATUS.contains(baseProtocolTunnel.getTunnelStatus())) {
					((DataSenderInterface) baseProtocolTunnel).updateData2Protocol();
				} else {
					baseProtocolTunnel.getLog().info("通道监听串口或网口未成功");
				}
				return null;
			});
		}
		this.tasks.put(baseProtocolTunnel.getTunnelId(), callable);
	}

	@Override
	public String toString() {
		Map<String, JSONObject> str = new HashMap<>();
		this.tunnels.forEach((k, v) -> {
			str.put(k, v.getJSONObj());
		});
		return JSON.toJSONString(str);
	}

	/**
	 * 格式化打印信息 以表格的形式打印通道状态
	 *
	 * @return
	 */
	public String toStringFormatted() {
		StringBuffer stringBuffer = new StringBuffer();
		String splitLine = "|——————————————————————————————————|————————————————————|—————————————————————|———————————————————————|\n";
		stringBuffer.append(splitLine);
		stringBuffer.append("|              通道id              |       通道类型      |        通道状态      |         通道名        |\n");
		stringBuffer.append(splitLine);
		for (BaseProtocolTunnel t : this.tunnels.values()) {
			stringBuffer.append("|");
			stringBuffer.append(StringUtils.center(t.getTunnelInfo().getId(), 34));
			stringBuffer.append("|");
			stringBuffer.append(StringUtils.center(t.getTunnelInfo().getTunnelType().toString(), 20));
			stringBuffer.append("|");
			stringBuffer.append(StringUtils.center(t.getTunnelStatus().toString(), 21));
			stringBuffer.append("|");
			stringBuffer.append(StringUtils.center(t.getTunnelInfo().getTunnelName(), 20));
			stringBuffer.append("|");
			stringBuffer.append("\n");
			stringBuffer.append(splitLine);
		}
		return stringBuffer.toString();
	}

	/**
	 * 静态内部类 为了创建安全的单例
	 */
	private static class LazyHolder {
		private static final ProtocolTunnelContainer INSTANCE = new ProtocolTunnelContainer();
	}

	/**
	 * 创建一个对通道池内通道状态的检查任务
	 */
	class CheckTunnelStatusTask implements Callable {

		@Override
		public Object call() throws Exception {
			TunnelStatus tunnelStatus;
			log.info("开始对所有的通道状态进行巡检");
			Iterator<String> it = tunnels.keySet().iterator();
			String keyString;
			BaseProtocolTunnel tunnel;
			BaseTunnelInfo tunnelInfo;
			while (it.hasNext()) {
				keyString = it.next();
				tunnel = tunnels.get(keyString);
				tunnelInfo=tunnel.getTunnelInfo();
				tunnelStatus = tunnel.getTunnelStatus();
				if (!TunnelStatus.getRunningProperlyStatus().contains(tunnelStatus)) {
					log.warn("发现本该开启的通道:{} 处在未开启成功的状态,重启该通道", tunnelInfo.getTunnelName());
					try {
						tunnel.tunnelStop();
					} catch (DataExchangeException e) {
						log.error("通道{}关闭时发生异常", tunnelInfo.getTunnelName(), e);
					}
					tunnel.refreshTunnelInfo(tunnelInfo).buildTunnel();
					try {
						tunnel.startTunnel();
					} catch (DataExchangeException e) {
						log.error("通道{}开启时发生异常",tunnelInfo.getTunnelName(), e);
					}
				}
			}
			return null;
		}
	}


}
